home *** CD-ROM | disk | FTP | other *** search
/ InterCD 2001 May / may_2001.iso / intercd / root / Multimedia / ^DivX_Article / virtualdub / VirtualDub-source-1_4d / f_convolute.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2001-03-20  |  19.5 KB  |  687 lines

  1. //    VirtualDub - Video processing and capture application
  2. //    Copyright (C) 1998-2001 Avery Lee
  3. //
  4. //    This program is free software; you can redistribute it and/or modify
  5. //    it under the terms of the GNU General Public License as published by
  6. //    the Free Software Foundation; either version 2 of the License, or
  7. //    (at your option) any later version.
  8. //
  9. //    This program is distributed in the hope that it will be useful,
  10. //    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. //    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12. //    GNU General Public License for more details.
  13. //
  14. //    You should have received a copy of the GNU General Public License
  15. //    along with this program; if not, write to the Free Software
  16. //    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17.  
  18. #include "VirtualDub.h"
  19. #include <crtdbg.h>
  20. #include <stdio.h>
  21.  
  22. #include <windows.h>
  23.  
  24. #include "ScriptValue.h"
  25. #include "ScriptInterpreter.h"
  26. #include "ScriptError.h"
  27.  
  28. #include "resource.h"
  29. #include "filter.h"
  30. #include "dub.h"
  31.  
  32. #include "disasm.h"
  33.  
  34. #include "f_convolute.h"
  35.  
  36. #define USE_ASM
  37. #define USE_ASM_DYNAMIC
  38.  
  39. extern "C" void asm_convolute_run(
  40.         void *dst,
  41.         void *src,
  42.         unsigned long width,
  43.         unsigned long height,
  44.         unsigned long srcstride,
  45.         unsigned long dststride,
  46.         const long *matrix);
  47.  
  48. extern "C" void asm_dynamic_convolute_run(
  49.         void *dst,
  50.         void *src,
  51.         unsigned long width,
  52.         unsigned long height,
  53.         unsigned long srcstride,
  54.         unsigned long dststride,
  55.         const long *matrix,
  56.         const void *dyna_func);
  57.  
  58. extern HINSTANCE g_hInst;
  59.  
  60. ///////////////////////////////////
  61.  
  62. #define C_TOPOK        (1)
  63. #define C_BOTTOMOK    (2)
  64. #define C_LEFTOK    (4)
  65. #define C_RIGHTOK    (8)
  66.  
  67. static void inline conv_add(long& rt, long& gt, long& bt, unsigned long dv, long m) {
  68.     bt += m*(0xFFUL & (dv));
  69.     gt += m*(0xFFUL & (dv>>8));
  70.     rt += m*(0xFFUL & (dv>>16));
  71. }
  72.  
  73. /* conv_clip_tab: number of times center should be added */
  74.  
  75. static unsigned long __fastcall do_conv(unsigned long *data, const ConvoluteFilterData *cfd, long sflags, long pit) {
  76.     long rt0=cfd->m[9], gt0=cfd->m[9], bt0=cfd->m[9];
  77.     long rt,gt,bt;
  78.  
  79.     if (sflags & C_TOPOK) {
  80.         if (sflags & (C_LEFTOK))        conv_add(rt0, gt0, bt0, data[        -1], cfd->m[6]);
  81.         else                            conv_add(rt0, gt0, bt0, data[         0], cfd->m[6]);
  82.  
  83.                                         conv_add(rt0, gt0, bt0, data[         0], cfd->m[7]);
  84.  
  85.         if (sflags & (C_RIGHTOK))        conv_add(rt0, gt0, bt0, data[        +1], cfd->m[8]);
  86.         else                            conv_add(rt0, gt0, bt0, data[         0], cfd->m[8]);
  87.     } else {
  88.         // top is clipped... push down.
  89.  
  90.         if (sflags & (C_LEFTOK))        conv_add(rt0, gt0, bt0, data[(pit>>2)-1], cfd->m[6]);
  91.         else                            conv_add(rt0, gt0, bt0, data[(pit>>2)  ], cfd->m[6]);
  92.  
  93.                                         conv_add(rt0, gt0, bt0, data[(pit>>2)  ], cfd->m[7]);
  94.  
  95.         if (sflags & (C_RIGHTOK))        conv_add(rt0, gt0, bt0, data[(pit>>2)+1], cfd->m[8]);
  96.         else                            conv_add(rt0, gt0, bt0, data[(pit>>2)  ], cfd->m[8]);
  97.  
  98.     }
  99.  
  100.     if (sflags & (C_LEFTOK))            conv_add(rt0, gt0, bt0, data[(pit>>2)-1], cfd->m[3]);
  101.     else                                conv_add(rt0, gt0, bt0, data[(pit>>2)  ], cfd->m[3]);
  102.  
  103.                                         conv_add(rt0, gt0, bt0, data[(pit>>2)  ], cfd->m[4]);
  104.  
  105.     if (sflags & (C_RIGHTOK))            conv_add(rt0, gt0, bt0, data[(pit>>2)+1], cfd->m[5]);
  106.     else                                conv_add(rt0, gt0, bt0, data[(pit>>2)  ], cfd->m[5]);
  107.  
  108.     if (sflags & C_BOTTOMOK) {
  109.         if (sflags & (C_LEFTOK))        conv_add(rt0, gt0, bt0, data[(pit>>1)-1], cfd->m[0]);
  110.         else                            conv_add(rt0, gt0, bt0, data[(pit>>1)  ], cfd->m[0]);
  111.  
  112.                                         conv_add(rt0, gt0, bt0, data[(pit>>1)  ], cfd->m[1]);
  113.  
  114.         if (sflags & (C_RIGHTOK))        conv_add(rt0, gt0, bt0, data[(pit>>1)+1], cfd->m[2]);
  115.         else                            conv_add(rt0, gt0, bt0, data[(pit>>1)  ], cfd->m[2]);
  116.     } else {
  117.         // bottom is clipped... push up.
  118.  
  119.         if (sflags & (C_LEFTOK))        conv_add(rt0, gt0, bt0, data[(pit>>2)-1], cfd->m[0]);
  120.         else                            conv_add(rt0, gt0, bt0, data[(pit>>2)  ], cfd->m[0]);
  121.  
  122.                                         conv_add(rt0, gt0, bt0, data[(pit>>2)  ], cfd->m[1]);
  123.  
  124.         if (sflags & (C_RIGHTOK))        conv_add(rt0, gt0, bt0, data[(pit>>2)+1], cfd->m[2]);
  125.         else                            conv_add(rt0, gt0, bt0, data[(pit>>2)  ], cfd->m[2]);
  126.     }
  127.  
  128.     rt = rt0>>8;    if (rt<0) rt=0; else if (rt>255) rt=255;
  129.     gt = gt0>>8;    if (gt<0) gt=0; else if (gt>255) gt=255;
  130.     bt = bt0>>8;    if (bt<0) bt=0; else if (bt>255) bt=255;
  131.  
  132.     return (unsigned long)((rt<<16) | (gt<<8) | (bt));
  133. }
  134.  
  135. static inline unsigned long do_conv2(unsigned long *data, const long *m, long pit) {
  136.     long rt0=m[9], gt0=m[9], bt0=m[9];
  137.     long rt,gt,bt;
  138.  
  139.     conv_add(rt0, gt0, bt0, data[        -1], m[6]);
  140.     conv_add(rt0, gt0, bt0, data[         0], m[7]);
  141.     conv_add(rt0, gt0, bt0, data[        +1], m[8]);
  142.     conv_add(rt0, gt0, bt0, data[(pit>>2)-1], m[3]);
  143.     conv_add(rt0, gt0, bt0, data[(pit>>2)  ], m[4]);
  144.     conv_add(rt0, gt0, bt0, data[(pit>>2)+1], m[5]);
  145.     conv_add(rt0, gt0, bt0, data[(pit>>1)-1], m[0]);
  146.     conv_add(rt0, gt0, bt0, data[(pit>>1)  ], m[1]);
  147.     conv_add(rt0, gt0, bt0, data[(pit>>1)+1], m[2]);
  148.  
  149.     rt = rt0>>8;    if (rt<0) rt=0; else if (rt>255) rt=255;
  150.     gt = gt0>>8;    if (gt<0) gt=0; else if (gt>255) gt=255;
  151.     bt = bt0>>8;    if (bt<0) bt=0; else if (bt>255) bt=255;
  152.  
  153.     return (unsigned long)((rt<<16) | (gt<<8) | (bt));
  154. }
  155.  
  156. int filter_convolute_run(const FilterActivation *fa, const FilterFunctions *ff) {
  157.     unsigned long w,h;
  158.     unsigned long *src = (unsigned long *)fa->src.data, *dst = (unsigned long *)fa->dst.data;
  159.     unsigned long pitch = fa->src.pitch;
  160.     const ConvoluteFilterData *cfd = (ConvoluteFilterData *)fa->filter_data;
  161.     const long *const m = cfd->m;
  162.  
  163. #ifdef USE_ASM
  164. #ifdef USE_ASM_DYNAMIC
  165.     if (((ConvoluteFilterData *)fa->filter_data)->dyna_func)
  166.         asm_dynamic_convolute_run(dst+(fa->dst.pitch>>2)+1, src, fa->src.w-2, fa->src.h-2, fa->dst.pitch, fa->src.pitch, m, ((ConvoluteFilterData *)fa->filter_data)->dyna_func);
  167.     else
  168. #endif
  169.         asm_convolute_run(dst+(fa->dst.pitch>>2)+1, src, fa->src.w-2, fa->src.h-2, fa->dst.pitch, fa->src.pitch, m);
  170. #endif
  171.  
  172.     src -= pitch>>2;
  173.  
  174.     *dst++ = do_conv(src++, cfd, C_BOTTOMOK | C_RIGHTOK, pitch);
  175.     w = fa->src.w-2;
  176.     do { *dst++ = do_conv(src++, cfd, C_BOTTOMOK | C_LEFTOK | C_RIGHTOK, pitch); } while(--w);
  177.     *dst++ = do_conv(src++, cfd, C_BOTTOMOK | C_LEFTOK, pitch);
  178.  
  179.     src += fa->src.modulo>>2;
  180.     dst += fa->dst.modulo>>2;
  181.  
  182. #ifndef USE_ASM
  183.     h = fa->src.h-2;
  184.     do {
  185.         *dst++ = do_conv(src++, cfd, C_TOPOK | C_BOTTOMOK | C_RIGHTOK, pitch);
  186.         w = fa->src.w-2;
  187.         do { *dst++ = do_conv2(src++, m, pitch); } while(--w);
  188.         *dst++ = do_conv(src++, cfd, C_TOPOK | C_BOTTOMOK | C_LEFTOK, pitch);
  189.  
  190.         src += fa->src.modulo>>2;
  191.         dst += fa->dst.modulo>>2;
  192.     } while(--h);
  193. #else
  194.     h = fa->src.h-2;
  195.     w = fa->src.w;
  196.     do {
  197.         dst[0] = do_conv(src+0, cfd, C_TOPOK | C_BOTTOMOK | C_RIGHTOK, pitch);
  198.         dst[w-1] = do_conv(src+w-1, cfd, C_TOPOK | C_BOTTOMOK | C_LEFTOK, pitch);
  199.  
  200.         src += fa->src.pitch>>2;
  201.         dst += fa->dst.pitch>>2;
  202.     } while(--h);
  203. #endif
  204.  
  205.     *dst++ = do_conv(src++, cfd, C_TOPOK | C_RIGHTOK, pitch);
  206.     w = fa->src.w-2;
  207.     do { *dst++ = do_conv(src++, cfd, C_TOPOK | C_LEFTOK | C_RIGHTOK, pitch); } while(--w);
  208.     *dst++ = do_conv(src++, cfd, C_TOPOK | C_LEFTOK, pitch);
  209.  
  210.     return 0;
  211. }
  212.  
  213. long filter_convolute_param(FilterActivation *fa, const FilterFunctions *ff) {
  214.     return FILTERPARAM_SWAP_BUFFERS;
  215. }
  216.  
  217. //////////////////
  218.  
  219. static int convolute_init(FilterActivation *fa, const FilterFunctions *ff) {
  220.     ((ConvoluteFilterData *)fa->filter_data)->m[4] = 256;
  221.     ((ConvoluteFilterData *)fa->filter_data)->bias = 128;
  222.     ((ConvoluteFilterData *)fa->filter_data)->dyna_func = NULL;
  223.  
  224.     return 0;
  225. }
  226.  
  227. static BOOL APIENTRY convoluteDlgProc( HWND hDlg, UINT message, UINT wParam, LONG lParam) {
  228.     int i;
  229.  
  230.     switch (message)
  231.     {
  232.         case WM_INITDIALOG:
  233.             {
  234.                 struct ConvoluteFilterData *cfd = (ConvoluteFilterData *)lParam;
  235.  
  236.                 CheckDlgButton(hDlg, IDC_ENABLE_CLIPPING, cfd->fClip);
  237.                 SetDlgItemInt(hDlg, IDC_BIAS, (cfd->bias-128)>>8, TRUE);
  238.  
  239.                 for(i=0; i<9; i++)
  240.                     SetDlgItemInt(hDlg, IDC_MATRIX_1+i, cfd->m[i], TRUE);
  241.  
  242.                 SetWindowLong(hDlg, DWL_USER, (LONG)cfd);
  243.             }
  244.             return (TRUE);
  245.  
  246.         case WM_COMMAND:                      
  247.             if (LOWORD(wParam) == IDOK) {
  248.                 struct ConvoluteFilterData *cfd = (struct ConvoluteFilterData *)GetWindowLong(hDlg, DWL_USER);
  249.  
  250.                 cfd->fClip = IsDlgButtonChecked(hDlg, IDC_ENABLE_CLIPPING);
  251.                 cfd->bias = GetDlgItemInt(hDlg, IDC_BIAS, NULL, TRUE)*256 + 128;
  252.  
  253.                 for(i=0; i<9; i++)
  254.                     cfd->m[i] = GetDlgItemInt(hDlg, IDC_MATRIX_1+i, NULL, TRUE);
  255.  
  256.                 EndDialog(hDlg, 0);
  257.                 return TRUE;
  258.             } else if (LOWORD(wParam) == IDCANCEL) {
  259.                 EndDialog(hDlg, 1);  
  260.                 return TRUE;
  261.             }
  262.             break;
  263.     }
  264.     return FALSE;
  265. }
  266.  
  267. static int convolute_config(FilterActivation *fa, const FilterFunctions *ff, HWND hWnd) {
  268.     return DialogBoxParam(g_hInst, MAKEINTRESOURCE(IDD_FILTER_CONVOLUTE), hWnd, convoluteDlgProc, (LONG)fa->filter_data);
  269. }
  270.  
  271. static void convolute_script_config(IScriptInterpreter *isi, void *lpVoid, CScriptValue *argv, int argc) {
  272.     FilterActivation *fa = (FilterActivation *)lpVoid;
  273.     int lv = argv[0].asInt();
  274.  
  275.     ConvoluteFilterData *cfd = (ConvoluteFilterData *)fa->filter_data;
  276.  
  277.     for(int i=0; i<9; i++) {
  278.         cfd->m[i] = argv[i].asInt();
  279.     }
  280.  
  281.     cfd->bias = argv[9].asInt();
  282.     cfd->fClip = !!argv[10].asInt();
  283. }
  284.  
  285. static ScriptFunctionDef convolute_func_defs[]={
  286.     { (ScriptFunctionPtr)convolute_script_config, "Config", "0iiiiiiiiiii" },
  287.     { NULL },
  288. };
  289.  
  290. static CScriptObject convolute_obj={
  291.     NULL, convolute_func_defs
  292. };
  293.  
  294. static bool convolute_script_line(FilterActivation *fa, const FilterFunctions *ff, char *buf, int buflen) {
  295.     ConvoluteFilterData *cfd = (ConvoluteFilterData *)fa->filter_data;
  296.  
  297.     _snprintf(buf, buflen, "Config(%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d)"
  298.             ,cfd->m[0]
  299.             ,cfd->m[1]
  300.             ,cfd->m[2]
  301.             ,cfd->m[3]
  302.             ,cfd->m[4]
  303.             ,cfd->m[5]
  304.             ,cfd->m[6]
  305.             ,cfd->m[7]
  306.             ,cfd->m[8]
  307.             ,cfd->bias
  308.             ,cfd->fClip?1:0
  309.             );
  310.  
  311.     return true;
  312. }
  313.  
  314. ///////////////////////////////////
  315.  
  316. extern DubOptions g_dubOpts;
  317.  
  318. #define REG_EAX        (0)
  319. #define REG_ECX        (1)
  320. #define REG_EDX        (2)
  321. #define REG_EBX        (3)
  322. #define REG_ESP        (4)
  323. #define REG_EBP        (5)
  324. #define REG_ESI        (6)
  325. #define REG_EDI        (7)
  326.  
  327. char *DCG_emit_MOV(char *ptr, int dest, int src) {
  328.     ptr[0] = (char)0x8b;
  329.     ptr[1] = 0xc0 + (dest<<3) + src;
  330.  
  331.     return ptr+2;
  332. }
  333.  
  334. char *DCG_emit_MOV_from_indexed(char *ptr, int dest, int src, long disp32) {
  335.     ptr[0] = (char)0x8b;
  336.     if (src != REG_ESP) {
  337.         if (src != REG_EBP && !disp32) {
  338.             ptr[1] = (dest<<3) + src;
  339.             return ptr+2;
  340.         }
  341.         if (disp32>=-128 && disp32<128) {
  342.             ptr[1] = 0x40 + (dest<<3) + src;
  343.             ptr[2] = disp32 & 0xff;
  344.             return ptr+3;
  345.         }
  346.         ptr[1] = 0x80 + (dest<<3) + src;
  347.         *(long *)(ptr+2) = disp32;
  348.         return ptr+6;
  349.     }
  350.  
  351.     ptr[2] = 0x24;
  352.     if (!disp32) {
  353.         ptr[1] = 0x00 + (dest<<3);
  354.         return ptr+3;
  355.     }
  356.     if (disp32>=-128 && disp32<128) {
  357.         ptr[1] = 0x40 + (dest<<3);
  358.         ptr[3] = 0;
  359.         return ptr+4;
  360.     }
  361.     ptr[1] = 0x80 + (dest<<3);
  362.     *(long *)(ptr+3) = 0;
  363.     return ptr+7;
  364. }
  365.  
  366. char *DCG_emit_ADD(char *ptr, int dest, int src) {
  367.     ptr[0] = 0x03;
  368.     ptr[1] = 0xc0 + (dest<<3) + src;
  369.  
  370.     return ptr+2;
  371. }
  372.  
  373. char *DCG_emit_SUB(char *ptr, int dest, int src) {
  374.     ptr[0] = 0x2B;
  375.     ptr[1] = 0xc0 + (dest<<3) + src;
  376.  
  377.     return ptr+2;
  378. }
  379.  
  380. char *DCG_emit_SHL(char *ptr, int dest, int bits) {
  381.     if (bits==1) {
  382.         ptr[0] = (char)0xd1;
  383.         ptr[1] = 0xe0 + dest;
  384.  
  385.         return ptr+2;
  386.     }
  387.     ptr[0] = (char)0xc1;
  388.     ptr[1] = 0xe0 + dest;
  389.     ptr[2] = bits;
  390.  
  391.     return ptr+3;
  392. }
  393.  
  394. char *DCG_emit_SHR(char *ptr, int dest, int bits) {
  395.     if (bits==1) {
  396.         ptr[0] = (char)0xd1;
  397.         ptr[1] = 0xe8 + dest;
  398.  
  399.         return ptr+2;
  400.     }
  401.     ptr[0] = (char)0xc1;
  402.     ptr[1] = 0xe8 + dest;
  403.     ptr[2] = bits;
  404.  
  405.     return ptr+3;
  406. }
  407.  
  408. char *DCG_emit_AND_immediate(char *ptr, int dest, long imm32) {
  409.     ptr[0] = (char)0x81;
  410.     ptr[1] = 0xe0 + dest;
  411.     *(long *)(ptr+2) = imm32;
  412.  
  413.     return ptr+6;
  414. }
  415.  
  416. // LEA dest,[src1*scale] (scale = 0 to 3)
  417.  
  418. char *DCG_emit_LEA(char *ptr, int dest, int src1, int scale) {
  419.     ptr[0] = (char)0x8d;
  420.     if (!scale && src1!=REG_EBP && src1!=REG_ESP) {
  421.         ptr[1] = (dest<<3) | src1;
  422.         return ptr+2;
  423.     }
  424.     ptr[1] = 0x04 | (dest<<3);
  425.     ptr[2] = (scale<<6) | (src1<<3) | 0x05;
  426.     *(long *)(ptr+3)=0;
  427.  
  428.     return ptr+7;
  429. }
  430.  
  431. // LEA dest,[src2 + src1*scale]
  432.  
  433. char *DCG_emit_LEA(char *ptr, int dest, int src1, int scale, int src2) {
  434.     ptr[0] = (char)0x8d;
  435.     if (src2 == REG_EBP) {
  436.         ptr[1] = 0x44 | (dest<<3);
  437.         ptr[2] = (scale<<6) | (src1<<3) | src2;
  438.         ptr[3] = 0;
  439.         return ptr+4;
  440.     }
  441.     ptr[1] = 0x04 | (dest<<3);
  442.     ptr[2] = (scale<<6) | (src1<<3) | src2;
  443.  
  444.     return ptr+3;
  445. }
  446.  
  447. enum {
  448.     CODE_LEA1    = 0,    // 2 dest * 2 src1 * 2 src2 * 4 multipliers = 32 ops
  449.     CODE_LEA2    = 32,    // 2 dest * 2 src1 * 4 multipliers = 16 ops
  450.     CODE_SHL    = 48,    // 2 dest * 16 shifts = 32 ops
  451.     CODE_SUB    = 80,    // 2 dest * 2 src = 4 ops
  452.     CODE_MAX    = 84
  453. };
  454.  
  455. // src2(16), multiplier(4), src1(2), dest(1)
  456.  
  457. char *DCG_emit_mult_op(char *ptr, int reg1, int reg2, char op) {
  458.     if (op < CODE_LEA2) {
  459.         // special cases:
  460.         //        add - scale=1, src1=dest or src2=dest
  461.  
  462.         if (!(op&12) && !((op ^ (op>>1))&1))
  463.             return DCG_emit_ADD(ptr, op&1 ? reg2 : reg1, op&16 ? reg2 : reg1);
  464.         else if (!(op&12) && !((op ^ (op>>4))&1))
  465.             return DCG_emit_ADD(ptr, op&1 ? reg2 : reg1, op&2 ? reg2 : reg1);
  466.         else
  467.             return DCG_emit_LEA(
  468.                     ptr,
  469.                     op&1 ? reg2 : reg1,
  470.                     op&2 ? reg2 : reg1,
  471.                     (op>>2) & 3,
  472.                     op&16 ? reg2 : reg1);
  473.     } else if (op < CODE_SHL) {
  474.         // special cases:
  475.         //        mov - scale=1
  476.  
  477.         if (!((op>>2)&3))
  478.             return DCG_emit_MOV(ptr, op&1 ? reg2 : reg1, op&2 ? reg2 : reg1);
  479.         else
  480.             return DCG_emit_LEA(
  481.                     ptr,
  482.                     op&1 ? reg2 : reg1,
  483.                     op&2 ? reg2 : reg1,
  484.                     (op>>2) & 3);
  485.     } else if (op < CODE_SUB) {
  486.         // special cases:
  487.         //        add - shift=1
  488.  
  489.         if (((op-CODE_SHL)>>1)==1)
  490.             return DCG_emit_ADD(ptr, op&1?reg2:reg1, op&1?reg2:reg1);
  491.         else
  492.             return DCG_emit_SHL(ptr, op&1?reg2:reg1, (op - CODE_SHL)>>1);
  493.     } else {
  494.         return DCG_emit_SUB(ptr, op&1?reg2:reg1, op&2?reg2:reg1);
  495.     }
  496. }
  497.  
  498. extern "C" char *asm_dynamic_convolute_codecopy(char *, int);
  499. extern "C" const char *const asm_const_multiply_tab[2049];
  500.  
  501. int filter_convolute_start(FilterActivation *fa, const FilterFunctions *ff) {
  502.     ConvoluteFilterData *cfd = (ConvoluteFilterData *)fa->filter_data;
  503.     char *pptr,c;
  504.     const char *pcode;
  505.     int x, y;
  506.     long m;
  507.  
  508.     ///////////////
  509.  
  510.     if (!g_dubOpts.perf.dynamicEnable) return 0;
  511.  
  512.     if (!(cfd->dyna_func = allocmem(4096))) return 1;
  513.  
  514.     pptr = (char *)cfd->dyna_func;
  515.  
  516.     _RPT0(0,"Generating code.\n");
  517.  
  518.     pptr = asm_dynamic_convolute_codecopy(pptr, 0);
  519.  
  520.     for(y=0; y<3; y++)
  521.         for(x=0; x<3; x++) {
  522.             m = cfd->m[(2-y)*3+x];
  523.             if (!m) continue;
  524.  
  525.             _RPT3(0,"Matrix (%d,%d): coefficient %ld\n", x, y, m);
  526.  
  527.             // MOV eax,[esi+disp32]
  528.             // SHR eax,(0/8/16)
  529.             // AND eax,000000ffh
  530.             // (generate multiplication series)
  531.  
  532.             // red=EBP, green=EDI, blue=EDX
  533.  
  534.             // If the coefficient is 2, 4, or 8, generate a compact LEA sequence
  535.  
  536.             if (m==2 || m==4 || m==8) {
  537.                 int scale = m>>2;
  538.  
  539.                 // v MOV eax,[esi+disp32]
  540.                 // u MOV ebx,eax
  541.                 // v AND eax,000000ffh            eax: ready
  542.                 // u MOV ecx,ebx
  543.                 // v AND ebx,0000ff00h
  544.                 // u SHR ebx,8                    ebx: ready
  545.                 // v AND ecx,00ff0000h
  546.                 // u SHR ecx,16
  547.                 // v LEA edx,[edx+eax*mult]
  548.                 // u LEA edi,[edi+ebx*mult]
  549.                 // v LEA ebp,[ebp+ecx*mult]        ;AGI (arrgh!!!)
  550.  
  551.                 pptr = DCG_emit_MOV_from_indexed(pptr, REG_EAX, REG_ESI, fa->src.pitch*y + 4*x - 4);
  552.                 pptr = DCG_emit_MOV(pptr, REG_EBX, REG_EAX);
  553.                 pptr = DCG_emit_AND_immediate(pptr, REG_EAX, 0x000000ff);
  554.                 pptr = DCG_emit_MOV(pptr, REG_ECX, REG_EBX);
  555.                 pptr = DCG_emit_AND_immediate(pptr, REG_EBX, 0x0000ff00);
  556.                 pptr = DCG_emit_SHR(pptr, REG_EBX, 8);
  557.                 pptr = DCG_emit_AND_immediate(pptr, REG_ECX, 0x00ff0000);
  558.                 pptr = DCG_emit_SHR(pptr, REG_ECX, 16);
  559.                 pptr = DCG_emit_LEA(pptr, REG_EDX, REG_EAX, scale, REG_EDX);
  560.                 pptr = DCG_emit_LEA(pptr, REG_EDI, REG_EBX, scale, REG_EDI);
  561.                 pptr = DCG_emit_LEA(pptr, REG_EBP, REG_ECX, scale, REG_EBP);
  562.  
  563.             // If the coefficient is <=256, then generate red and blue simultaneously
  564.  
  565.             } else if (abs(m)<=256) {
  566.  
  567.                 pptr = DCG_emit_MOV_from_indexed(pptr, REG_EAX, REG_ESI, fa->src.pitch*y + 4*x - 4);
  568.                 pptr = DCG_emit_AND_immediate(pptr, REG_EAX, 0x00ff00ff);
  569.  
  570.                 pcode = asm_const_multiply_tab[abs(m)];
  571.                 while((c=*pcode++) != (char)0xff) {
  572.                     pptr = DCG_emit_mult_op(pptr, REG_EAX, REG_EBX, c);
  573.                 }
  574.  
  575.                 pptr = DCG_emit_MOV(pptr, REG_EBX, REG_EAX);
  576.  
  577.                 pptr = DCG_emit_SHR(pptr, REG_EAX, 16);
  578.                 pptr = DCG_emit_AND_immediate(pptr, REG_EBX, 0x0000ffff);
  579.  
  580.                 if (m<0)    pptr = DCG_emit_SUB(pptr, REG_EBP, REG_EAX);
  581.                 else        pptr = DCG_emit_ADD(pptr, REG_EBP, REG_EAX);
  582.  
  583.                 if (m<0)    pptr = DCG_emit_SUB(pptr, REG_EDX, REG_EBX);
  584.                 else        pptr = DCG_emit_ADD(pptr, REG_EDX, REG_EBX);
  585.  
  586.             } else {
  587.  
  588.                 // red
  589.  
  590.                 pptr = DCG_emit_MOV_from_indexed(pptr, REG_EAX, REG_ESI, fa->src.pitch*y + 4*x - 4);
  591.                 pptr = DCG_emit_SHR(pptr, REG_EAX, 16);
  592.                 pptr = DCG_emit_AND_immediate(pptr, REG_EAX, 0x000000ff);
  593.  
  594.                 pcode = asm_const_multiply_tab[abs(m)];
  595.                 while((c=*pcode++) != (char)0xff) {
  596.                     pptr = DCG_emit_mult_op(pptr, REG_EAX, REG_EBX, c);
  597.                 }
  598.  
  599.                 if (m<0)    pptr = DCG_emit_SUB(pptr, REG_EBP, REG_EAX);
  600.                 else        pptr = DCG_emit_ADD(pptr, REG_EBP, REG_EAX);
  601.  
  602.                 // blue
  603.  
  604.                 pptr = DCG_emit_MOV_from_indexed(pptr, REG_EAX, REG_ESI, fa->src.pitch*y + 4*x - 4);
  605.                 pptr = DCG_emit_AND_immediate(pptr, REG_EAX, 0x000000ff);
  606.  
  607.                 pcode = asm_const_multiply_tab[abs(m)];
  608.                 while((c=*pcode++) != (char)0xff)
  609.                     pptr = DCG_emit_mult_op(pptr, REG_EAX, REG_EBX, c);
  610.  
  611.                 if (m<0)    pptr = DCG_emit_SUB(pptr, REG_EDX, REG_EAX);
  612.                 else        pptr = DCG_emit_ADD(pptr, REG_EDX, REG_EAX);
  613.             }
  614.  
  615.             // green
  616.  
  617.             pptr = DCG_emit_MOV_from_indexed(pptr, REG_EAX, REG_ESI, fa->src.pitch*y + 4*x - 4);
  618.             pptr = DCG_emit_AND_immediate(pptr, REG_EAX, 0x0000ff00);
  619.  
  620.             pcode = asm_const_multiply_tab[abs(m)];
  621.             while((c=*pcode++) != (char)0xff)
  622.                 pptr = DCG_emit_mult_op(pptr, REG_EAX, REG_EBX, c);
  623.  
  624.             if (m<0)    pptr = DCG_emit_SUB(pptr, REG_EDI, REG_EAX);
  625.             else        pptr = DCG_emit_ADD(pptr, REG_EDI, REG_EAX);
  626.  
  627.  
  628.             _RPT3(0,"Finished (%d,%d) - %ld bytes of code so far\n", x, y, pptr - (char *)cfd->dyna_func);
  629.         }
  630.  
  631.     if (cfd->bias)
  632.         pptr = asm_dynamic_convolute_codecopy(pptr, 1);
  633.  
  634.     pptr = asm_dynamic_convolute_codecopy(pptr, 2);
  635.  
  636.     pptr[0] = 0x0f;
  637.     pptr[1] = (char)0x85;
  638.     *(long *)(pptr+2) = (char *)cfd->dyna_func - (pptr+6);
  639.     pptr[6] = (char)0xc3;    // RET
  640.  
  641.     cfd->dyna_size = (pptr+6) - (char *)cfd->dyna_func;
  642.  
  643.     VirtualProtect(cfd->dyna_func, cfd->dyna_size, PAGE_EXECUTE_READWRITE, &cfd->dyna_old_protect);
  644.  
  645.     //////
  646.  
  647.     if (g_dubOpts.perf.dynamicShowDisassembly) {
  648.         CodeDisassemblyWindow cdw(cfd->dyna_func, cfd->dyna_size, cfd->dyna_func, cfd->dyna_func);
  649.  
  650.         cdw.post(NULL);
  651.     }
  652.  
  653.     return 0;
  654. }
  655.  
  656. ///////////////////////////////////
  657.  
  658. int filter_convolute_end(FilterActivation *fa, const FilterFunctions *ff) {
  659.     ConvoluteFilterData *cfd = (ConvoluteFilterData *)fa->filter_data;
  660.  
  661.     if (cfd->dyna_func) {
  662.         VirtualProtect(cfd->dyna_func, cfd->dyna_size, cfd->dyna_old_protect, &cfd->dyna_old_protect);
  663.         freemem(cfd->dyna_func);
  664.         cfd->dyna_func = NULL;
  665.     }
  666.  
  667.     return 0;
  668. }
  669.  
  670. FilterDefinition filterDef_convolute={
  671.     0,0,NULL,
  672.     "general convolution",
  673.     "Applies a general 3x3 convolution matrix to a pixel that depends on the pixel's value and the eight neighboring pixels around it.\n\n"
  674.         "[Assembly optimized] [Dynamic compilation]",
  675.     NULL,NULL,
  676.     sizeof(ConvoluteFilterData),
  677.     convolute_init,
  678.     NULL,
  679.     filter_convolute_run,
  680.     filter_convolute_param,
  681.     convolute_config,
  682.     NULL,
  683.     filter_convolute_start,
  684.     filter_convolute_end,
  685.     &convolute_obj,
  686.     convolute_script_line,
  687. };